package org.ehe.business.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.business.overdue.config.OverdueStatus;
import org.ehe.business.overdue.service.ove.SolutionOverdueService;
import org.ehe.business.project.domain.ProjectSolution;
import org.ehe.business.project.domain.bo.ProjectSolutionBo;
import org.ehe.business.project.domain.vo.ProjectSolutionVO;
import org.ehe.business.project.mapper.ProjectSolutionMapper;
import org.ehe.business.project.service.ProjectSolutionService;
import org.ehe.business.timeout.contants.BizTypeConstant;
import org.ehe.business.timeout.mapper.TimeoutConfigMapper;
import org.ehe.business.timeout.service.TimeoutConfigService;
import org.ehe.common.core.constant.ProjectConstants;
import org.ehe.common.core.domain.dto.StartProcessDTO;
import org.ehe.common.core.domain.dto.StartProcessReturnDTO;
import org.ehe.common.core.service.WorkflowService;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.erp.enums.ErpAuditStatus;
import org.ehe.system.domain.vo.SysOssVo;
import org.ehe.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 *
 * @author :zhangnn
 * @className :ProjectSolutionServiceImpl
 * @description: TODO
 * @date 2025-07-25 11:50:58
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ProjectSolutionServiceImpl extends ServiceImpl<ProjectSolutionMapper, ProjectSolution> implements ProjectSolutionService {
    private final ISysOssService ossService;
    private final WorkflowService workflowService;
    private final TimeoutConfigMapper timeoutConfigMapper;
    /**
     * 方案分页
     * @param bo
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<ProjectSolutionVO> pageSolutions(ProjectSolutionBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ProjectSolution> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotBlank(bo.getSolutionName()),ProjectSolution::getSolutionName,bo.getSolutionName());
        lqw.like(StringUtils.isNotBlank(bo.getProjectName()),ProjectSolution::getProjectName,bo.getProjectName());
        lqw.orderByDesc(ProjectSolution::getUpdateTime);
        Page<ProjectSolutionVO> result = this.baseMapper.selectVoPage(pageQuery.build(), lqw);
        for (ProjectSolutionVO record : result.getRecords()) {
            solutionStatusName(record);
        }
        return TableDataInfo.build(result);
    }

    /**
     * 新增项目方案
     * @param request
     * @return
     */
    @Override
    public int createProjectSoution(ProjectSolution request) {
        // 验证版本是否存在
        validateVersionExists(request.getProjectId(), request.getVersion());

        request.setCreateBy(LoginHelper.getUsername());
        request.setTenantId(LoginHelper.getTenantId());
        request.setStatus(ProjectConstants.PROJECT_SOLUTION_CG); //草稿未提交
        request.setApproveStatus(ErpAuditStatus.PENDING_SUBMIT.getStatus().toString());
        //超期时间1小时
        request.setIsOverdue(OverdueStatus.PENDING);
        int hours = timeoutConfigMapper.getTimeByBizType(BizTypeConstant.SOLUTION);
        request.setIsOverdueEndTime(LocalDateTime.now().plusHours(hours));
        int insert = this.baseMapper.insert(request);

        //发起工作流程
       request.setId(request.getId());


        return insert;
    }

    /**
     * 修改项目方案
     * @param request
     * @return
     */
    @Override
    public int updateProjectSolution(ProjectSolution request) {
        // 查询现有方案
        ProjectSolution existingSolution = getExistingSolution(request.getProjectId(), request.getVersion());
        if(Objects.isNull(existingSolution) && null != request.getId()){
            existingSolution = this.baseMapper.selectById(request.getId());
        }
        if (existingSolution == null) {
            // 版本不存在，创建新版本
            return createNewVersion(request);
        } else {
            // 版本存在，检查是否可以修改
            //validateCanModify(existingSolution);
            ProjectSolution projectSolution = new ProjectSolution();
            BeanUtils.copyProperties(existingSolution,projectSolution);
            projectSolution.setIsOverdueEndTime(existingSolution.getIsOverdueEndTime());
            projectSolution.setIsOverdue(request.getIsOverdue());
            projectSolution.setEstimatedHours(request.getEstimatedHours());
            //projectSolution.setApproveStatus(request.getApproveStatus());
            projectSolution.setStatus(StringUtils.isBlank(request.getStatus())?existingSolution.getStatus():request.getStatus());

            return updateExistingSolution(projectSolution, existingSolution.getId());
        }
    }

    /**
     * 创建新版本
     * @param request
     * @return
     */
    private int createNewVersion(ProjectSolution request) {
        // 验证版本号是否递增
        validateVersionIncrement(request.getProjectId(), request.getVersion());

        request.setCreateBy(LoginHelper.getUsername());
        request.setTenantId(LoginHelper.getTenantId());
        request.setId(null); // 确保是新增

        return this.baseMapper.insert(request);
    }

    /**
     * 更新现有方案
     * @param request
     * @param existingId
     * @return
     */
    private int updateExistingSolution(ProjectSolution request, Long existingId) {
        request.setId(existingId);
        request.setUpdateBy(LoginHelper.getUsername());
        if (Integer.valueOf(request.getApproveStatus()) == ErpAuditStatus.SUBMITTED.getStatus() ||
          request.getEstimatedHours() > 0) {
            LocalDateTime endlineTime = LocalDateTime.now().plusDays(request.getEstimatedHours());
            request.setDeadlineTime(endlineTime);
            request.setApproveStatus(String.valueOf(ErpAuditStatus.SUBMITTED.getStatus()));
            //超期处理
            request.setIsOverdue(OverdueStatus.PROCESSED);
            //超期处理
            if(request.getIsOverdueEndTime().isBefore(LocalDateTime.now())){
                request.setIsOverdue(OverdueStatus.OVERDUE_AND_PROCESSED);
            }
        }
        if(request.getStatus().equals(ProjectConstants.PROJECT_SOLUTION_WC)){
            //判断是否超期
            request.setStatus(ProjectConstants.PROJECT_SOLUTION_WC);
            if (LocalDateTime.now().isAfter(request.getDeadlineTime())) {
                request.setStatus(ProjectConstants.PROJECT_SOLUTION_CQWC);
            }
        }
        int i = this.baseMapper.updateById(request);

        return i;
    }

    /**
     * 作废项目方案
     * @param id 方案ID
     * @return
     */
    public int invalidateProjectSolution(Long id) {
        ProjectSolution solution = this.baseMapper.selectById(id);
        if (solution == null) {
            throw new RuntimeException("方案不存在");
        }

        // 验证是否可以作废
        validateCanInvalidate(solution);

        solution.setStatus(ProjectConstants.PROJECT_SOLUTION_ZF);
        solution.setUpdateBy(LoginHelper.getUsername());
        return this.baseMapper.updateById(solution);
    }

    /**
     * 删除方案
     * @param id
     * @return
     */
    @Override
    public boolean deleteProjectSolution(Long id) {
        return removeById(id);
    }

    /**
     * 查看详情
     * @param id
     * @return
     */
    @Override
    public ProjectSolutionVO viewProjectSolution(Long id) {
        ProjectSolution solution = this.baseMapper.selectById(id);
        ProjectSolutionVO vo = new ProjectSolutionVO();
        BeanUtils.copyProperties(solution,vo);
        List<SysOssVo> ossVoList = new ArrayList<>();
        String solutionFiles = vo.getSolutionFiles();
        if (StringUtils.isNotBlank(solutionFiles)) {
            if(solutionFiles.contains(",")){
                Arrays.asList(solutionFiles.split(",")).forEach(s->{
                    SysOssVo ossVo = ossService.getById(Long.valueOf(s));
                    ossVoList.add(ossVo);
                });
            } else {
                SysOssVo ossVo = ossService.getById(Long.valueOf(solutionFiles));
                ossVoList.add(ossVo);
            }
        }
        solutionStatusName(vo);
        vo.setOssVo(ossVoList);
        return vo;
    }
    /**
     * 验证版本是否已存在
     * @param projectId
     * @param version
     */
    private void validateVersionExists(Long projectId, String version) {
        LambdaQueryWrapper<ProjectSolution> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProjectSolution::getProjectId, projectId)
            .eq(ProjectSolution::getVersion, version);

        long count = this.baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new RuntimeException("该项目的版本号 " + version + " 已存在，请使用其他版本号");
        }
    }
    /**
     * 获取现有方案
     * @param projectId
     * @param version
     * @return
     */
    private ProjectSolution getExistingSolution(Long projectId, String version) {
        LambdaQueryWrapper<ProjectSolution> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProjectSolution::getProjectId, projectId)
            .eq(ProjectSolution::getVersion, version);
        return this.baseMapper.selectOne(wrapper);
    }

    /**
     * 验证是否可以修改
     * @param solution
     */
    private void validateCanModify(ProjectSolution solution) {
        String status = solution.getStatus();
        if (!ErpAuditStatus.ALLOW_EDIT.contains(Integer.valueOf(status))) {
            throw new RuntimeException("只有草稿状态或未通过状态的方案才能修改");
        }
    }

    /**
     * 验证是否可以作废
     * @param solution
     */
    private void validateCanInvalidate(ProjectSolution solution) {
        String status = solution.getStatus();
        if (!ProjectConstants.PROJECT_SOLUTION_CG.equals(status) && !ProjectConstants.PROJECT_SOLUTION_SHZ.equals(status)) {
            throw new RuntimeException("只有草稿状态或未通过状态的方案才能作废");
        }
    }


    /**
     * 验证版本号是否递增
     * @param projectId
     * @param newVersion
     */
    private void validateVersionIncrement(Long projectId, String newVersion) {
        // 获取该项目的最新版本
        LambdaQueryWrapper<ProjectSolution> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProjectSolution::getProjectId, projectId)
            .orderByDesc(ProjectSolution::getVersion)
            .last("LIMIT 1");

        ProjectSolution latestSolution = this.baseMapper.selectOne(wrapper);
        if (latestSolution != null) {
            String latestVersion = latestSolution.getVersion();
            if (compareVersion(newVersion, latestVersion) <= 0) {
                throw new RuntimeException("新版本号必须大于当前最新版本 " + latestVersion);
            }
        }
    }

    /**
     * 比较版本号
     * @param version1
     * @param version2
     * @return 1: version1 > version2, 0: version1 = version2, -1: version1 < version2
     */
    private int compareVersion(String version1, String version2) {
        if (version1 == null || version2 == null) {
            return version1 == null ? -1 : 1;
        }

        try {
            // 简单的数值比较，假设版本号是数字形式
            double v1 = Double.parseDouble(version1);
            double v2 = Double.parseDouble(version2);
            return Double.compare(v1, v2);
        } catch (NumberFormatException e) {
            // 如果不是数字，则按字符串比较
            return version1.compareTo(version2);
        }
    }



    /**
     * 审核拒绝 - 启动超期监控
     */
    public ProjectSolution rejectSolution(Long solutionId, String auditUser) {
        ProjectSolution solution = this.baseMapper.selectById(solutionId);
        try {
            // 1. 更新方案状态为驳回
            solution.setAuditTime(LocalDateTime.now());
            solution.setAuditUser(auditUser);
            int hours = timeoutConfigMapper.getTimeByBizType(BizTypeConstant.SOLUTION);
            solution.setIsOverdue("0");
            solution.setStatus(ProjectConstants.PROJECT_SOLUTION_WTG); // 未通过
            solution.setApproveStatus(ErpAuditStatus.REJECTED.getStatus().toString()); //审批状态改为驳回
            solution.setIsOverdueEndTime(LocalDateTime.now().plusHours(hours));

            this.baseMapper.updateById(solution);

            // 2. 启动超期监控
            //solutionOverdueService.initOverdueMonitor(solution,hours);

            log.info("方案审核拒绝成功，已启动超期监控: solutionId={}", solutionId);

        } catch (Exception e) {
            log.error("审核拒绝失败: solutionId={}", solutionId, e);
            throw new RuntimeException("审核拒绝失败", e);
        }
        return solution;
    }

    /**
     * 提交 - 取消超期监控
     */
    public ProjectSolution resubmitSolution(Long solutionId,Integer days) {
        ProjectSolution solution = this.baseMapper.selectById(solutionId);
        try {
            // 1. 更新方案状态为审核中
            solution.setId(solutionId);
            //solution.setStatus(String.valueOf(ErpAuditStatus.SUBMITTED.getStatus()));
            solution.setIsOverdue(OverdueStatus.PROCESSED);
            if(solution.getIsOverdueEndTime().isBefore(LocalDateTime.now())){
                solution.setIsOverdue(OverdueStatus.OVERDUE_AND_PROCESSED);
            }
            solution.setEstimatedHours(days);
            solution.setStatus(ProjectConstants.PROJECT_SOLUTION_SHZ); //审核中
            solution.setApproveStatus(ErpAuditStatus.SUBMITTED.getStatus().toString());
            solution.setDeadlineTime(LocalDateTime.now().plusDays(days));

            this.baseMapper.updateById(solution);

            //发起工作流程
            if (solution.getApproveStatus().equals(ErpAuditStatus.SUBMITTED.getStatus().toString())) {
                StartProcessDTO process = new StartProcessDTO();
                Map<String,Object> map = new HashMap<>();
                map.put("type","projectSolution");
                process.setVariables(map);
                process.setFlowCode("projectSolution");
                process.setBusinessId(String.valueOf(solution.getId()));
                StartProcessReturnDTO processReturnDTO = workflowService.startWorkFlow(process);
                log.info("流程审批发起成功，已启动: solutionId={}, solutionName={}", solution.getId(), solution.getSolutionName());

                //自己提交的流程节点默认审批完成
                Long taskId = processReturnDTO.getTaskId();
                workflowService.completeTask(taskId,"完成方案预计所需时长:"+solution.getEstimatedHours()+"天");
            }

            // 2. 取消超期监控
            //solutionOverdueService.cancelOverdueMonitor(solution);
            log.info("方案重新提交成功，已取消超期监控: solutionId={}", solutionId);

        } catch (Exception e) {
            log.error("重新提交失败: solutionId={}", solutionId, e);
            throw new RuntimeException("重新提交失败", e);
        }
        return solution;
    }

    /**
     * 审核通过 - 取消超期监控
     */
    public ProjectSolution approveSolution(Long solutionId, String auditUser) {
        ProjectSolution solution = this.baseMapper.selectById(solutionId);

        try {
            // 1. 更新方案状态为通过
            solution.setStatus(ProjectConstants.PROJECT_SOLUTION_PROGRESS); // 进行中
            solution.setApproveStatus(String.valueOf(ErpAuditStatus.APPROVE.getStatus()));
            solution.setAuditTime(LocalDateTime.now());
            solution.setAuditUser(auditUser);
            this.baseMapper.updateById(solution);

            // 2. 取消超期监控
            //solutionOverdueService.cancelOverdueMonitor(solution);
            log.info("方案审核通过成功，已取消超期监控: solutionId={}", solutionId);
        } catch (Exception e) {
            log.error("审核通过失败: solutionId={}", solutionId, e);
            throw new RuntimeException("审核通过失败", e);
        }
        return solution;
    }

    /**
     * 更新项目时常
     * @param solutionId
     * @param days
     * @return
     */
    @Override
    public ProjectSolution submitDays(Long solutionId, Integer days) {
        ProjectSolution solution = this.baseMapper.selectById(solutionId);
        solution.setEstimatedHours(days);
        solution.setDeadlineTime(LocalDateTime.now().plusDays(days));

        if(solution.getIsOverdueEndTime().isBefore(LocalDateTime.now())){
            solution.setIsOverdue(OverdueStatus.OVERDUE_AND_PROCESSED);
        }
        solution.setStatus(OverdueStatus.PROCESSED);
        this.baseMapper.updateById(solution);
        return solution;
    }

    /**
     * 获取方案状态名称
     * @param vo
     */
    private static void solutionStatusName(ProjectSolutionVO vo) {
        switch (vo.getStatus()){
            case "0"://草稿（未提交)
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_CG);
                break;
            case "2"://审核中
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_SHZ);
                break;
            case "4"://通过
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_TG);
                break;
            case "5"://未通过
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_WTG);
                break;
            case "6": //作废
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_ZF);
                break;
            case "20"://已完成
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_WC);
                break;
            case "21"://超期完成
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_CQWC);
                break;
            case "22"://超期未完成
                vo.setStatusName(ProjectConstants.PROJECT_SOLUTION_NAME_CQWWC);
                break;
        }
    }
}
